#Copyright Okhtay Shoghi 2008

require 'test/unit/assertions'

require 'selenium/selenium'
require 'uranium/constants'
require 'uranium/loggerwrapper'
require 'uranium/utils'
require 'uranium/hash'

include Test::Unit::Assertions

class Browser
	attr_accessor :selenium

	@@default_locale	= $default_locale	|| 'en'
	@@default_browser = $default_browser || '*chrome'

	def self.kill_selenium
		selenium = Selenium::SeleneseInterpreter.new(SELENIUM_SERVER, $selenium_port, @@default_browser, "http://localhost/")
		selenium.do_command('shutDownSeleniumServer',[])
	end

	def initialize(browser_type=@@default_browser, locale=@@default_locale)
		Log.debug "Instantiate #{browser_type} with locale #{locale}"

		#set_ff_locale(locale) if (browser_type == '*chrome')
		#set_ie_locale(locale) if (browser_type == '*chrome')

		port = defined?($selenium_port) ? $selenium_port : '4444'

		puts "port: #{port}"
		@selenium = Selenium::SeleneseInterpreter.new(SELENIUM_SERVER, port, browser_type, "http://_blank/")
		@selenium.start
		@selenium.set_timeout(PAGE_LOAD_TIMEOUT)
	end
	
	def set_ie_locale(locale='en')
		if RUBY_PLATFORM.match(/win32/)
			require 'win32/registry'
		
			puts Win32::Registry::HKEY_CURRENT_USER.open('Software\\Microsoft\\Internet Explorer\\International', Win32::Registry::KEY_WRITE).write_s('AcceptLanguage','az')
		end
	end
	
	def set_ff_locale(locale='en')
		prefs_path = PATH_TO_FIREFOX_PROFILE + '/prefs.js'
		
		#load prefs file to memory
		prefs_js	 = File.open(prefs_path, 'r')
		buffer	 = prefs_js.read(File.size(prefs_path));
		prefs_js.close
					
		#if there is already a language setting remove from buffer
		buffer	 = buffer.gsub(/^.*?intl\.accept_languages.*?\);/,'')
		buffer	+= "\nuser_pref(\"intl.accept_languages\", \"#{locale}\");"
		
		#if we end up with two carriage returns, remove one
		buffer	 = buffer.gsub(/\n\n/,"\n")

		#write preferences to file
		prefs_js	 = File.open(prefs_path, File::RDWR|File::TRUNC)
		prefs_js.write(buffer)
		prefs_js.close()		
	end
	
	def close
		@selenium.stop
	end
	
	def	self.set_locale(locale)
		@@default_locale = locale
	end
	
	def self.set_browser(browser)
		@@default_browser = browser
	end
end

class Page
	attr_accessor :selenium
	
	@@title		= (defined?(@@title)		? @@title		: {})
	@@elements	= (defined?(@@elements) 	? @@elements	: {})
	@@opts		= (defined?(@@opts)			? @@opts		: {})
	@@url		= (defined?(@@url)			? @@url		 	: {})
	@@browser	= nil
	
	def self.get_error(err_str, sub=nil)
		error = ""
		eval("error = self::ERROR_#{err_str}")
		error.gsub!("__VAR__", sub) if sub
		
		return error
	end
	
	def self.inherit_parent_elements
		@@elements[self] = {} unless (@@elements.has_key?(self))
		@@elements[self] = @@elements[self].merge(@@elements[superclass]) if (@@elements.has_key?(superclass))
	end

	def initialize(args={})
		args.defaults 'go_on_init' => true,
					  'browser' => nil,
					  'inherit_parent_elements' => true
		
		self.class.inherit_parent_elements if (args['inherit_parent_elements'])

		init(args['browser'], args['go_on_init'])
	end

	def init(browser=nil, go_on_init=true)
		browser = @@browser ? @@browser : (@@browser = Browser.new) if not browser
		@selenium = browser.selenium
		
		goto_page if go_on_init
	end
	
	def load_url(url, wait=true)
		@selenium.open(url)
		wait_for_page_to_load if wait
	end

	def goto_page
		if (@@url[self.class])
			Log.debug "goto_page(#{@@url[self.class]})"
		
			load_url(@@url[self.class], (@@opts[self.class] && @@opts[self.class]['wait_for_page_to_load']))
		end
	end

	def verify_page
		wait_for_success do 
			assert_equal(@@url[self.class], @selenium.get_location)
		end
	end
	
	def wait_for_page_to_load
		@selenium.wait_for_page_to_load(30000)
	end
	
	def get_locator(element)
		return (@@elements[self.class].has_key?(element) ? @@elements[self.class][element] : "css=##{element}")
	end
	
	def eval_js_array(str)
		return @selenium.get_string_array('getEval',[str])
	end
	
	def eval_js(str)
		return @selenium.get_eval(str)
	end

	def eval_js_in_window(str)
		return eval_js("this.browserbot.getUserWindow().#{str}")
	end

	def reload
		eval_js_in_window("document.location.reload()")
	end
	
	def get_element_type(locator)
		return eval_js("this.page().findElement(\"#{locator}\").tagName").downcase
	end
	
	def get_attribute(locator, attr, wait=true)
		Log.debug "get_attribute #{attr} for #{locator}"

		wait_for_element(locator) if wait
		
		locator.gsub!('\"',"\\\"")
		return eval_js("this.page().findElement(\"#{locator}\").getAttribute('#{attr}')")
	end
	
	def is_text_present(text)
		return @selenium.is_text_present(text)
	end
	
	def wait_for_element(locator, needs_edit=true)
		wait_for_success do
			assert(@selenium.is_element_present(locator), "Element #{locator} not found")
			
			case(get_element_type(locator))
				when 'input','select','textarea'
					#do nothing
				else
					needs_edit = false
			end
			
			assert((!needs_edit or @selenium.is_editable(locator)), "Element #{locator} not editable")
		end
	end
	
	def click(locator, fire_event=true)
		Log.debug "clicking #{locator}"
		
		wait_for_element(locator)
		
		@selenium.click(locator)

		if (fire_event)
			@selenium.fire_event(locator, "mousedown")
			@selenium.fire_event(locator, "mouseup")
			@selenium.fire_event(locator, "click")
		end
	end
	
	def type(locator, str, fire_event=true)
		wait_for_element(locator)
		
		@selenium.type(locator, str)

		if (fire_event)
			@selenium.fire_event(locator, "keydown")
			@selenium.fire_event(locator, "keyup")
		end
	end
	
	def get_value(locator)
		Log.debug "get value for #{locator}"

		wait_for_element(locator)
	
		case(get_element_type(locator))
			when 'input', 'password','textarea','select'
				case(get_attribute(locator, 'type', false))
					when 'checkbox','radio'
						return (@selenium.get_value(locator) == 'on')
					else
						return @selenium.get_value(locator)
				end
			else
				return @selenium.get_text(locator)
		end
	end
	
	def set_value(locator, value, fireEvent=true)
		Log.debug "set #{locator} to #{value}"
	
		wait_for_element(locator)
		case(get_element_type(locator))
			when 'input', 'password'
				case(get_attribute(locator, 'type', false))
					when 'checkbox'
						click(locator) if ((@selenium.get_value(locator) == 'on') != value)
					when 'radio'
						click(locator)
					when 'file'
						@selenium.attach_file(locator, value)
					else
						type(locator, value)
				end
			when 'textarea'
				type(locator, value)
			when 'select'
				wait_for_success do 
					begin
						@selenium.select(locator, "value=#{value}")
					rescue
						@selenium.select(locator, value)
					end
				end
		end
	end
	
	def verify_value(locator, value)
		Log.debug "verify #{locator} has value #{value}"
		
		wait_for_success do
			assert_equal(value, get_value(locator))
		end
	end

	def verify_not_value(locator, value)
		Log.debug "verify #{locator}'s value is not #{value}"
		
		wait_for_success do
			assert(value != get_value(locator))
		end
	end
	
	def verify_enabled(locator)
		Log.debug "verify #{locator} is enabled"
	
		wait_for_success do 
			assert(@selenium.is_editable(locator))
		end
	end
	
	def verify_disabled(locator)
		Log.debug "verify #{locator} is disabled"
	
		wait_for_success do
			assert(!@selenium.is_editable(locator))
		end
	end
	
	def verify_visible(locator)
		Log.debug "verify #{locator} is visible"
	
		wait_for_success do
			assert(@selenium.is_visible(locator))
		end
	end
	
	def verify_not_visible(locator)
		Log.debug "verify #{locator} is not visible"
	
		wait_for_success do
			assert(!@selenium.is_visible(locator))
		end
	end
	
	def use_main_window
		Log.debug "use main window"
	
		@selenium.select_window('null')
	end

	def use_window(name)
		@Log.debug "use window #{name}"

		@selenium.select_window(name)
	end
	
	def close
		@selenium.stop if @selenium
		@@browser = nil
	end
	
	def method_missing(name, *args)
		Log.debug "method called: #{name}|"
	
		parts	 = name.to_s.split("_")
		command = parts[0]
		rest	= name.to_s.gsub("#{command}_", "")
		locator	= get_locator(rest)
		
		case(command)
			when "verify"
				case(parts[parts.length - 1])
					when "not"
						verify_not_value(get_locator(rest.sub(/(_is)?_not$/, "")))
					when "disabled"
						verify_disabled(get_locator(rest.sub(/(_is)?_disabled$/, "")))
					when "enabled"
						verify_enabled(get_locator(rest.sub(/(_is)?_enabled$/, "")))
					when "checked"
						if (rest.match(/not_checked$/))
							verify_value(get_locator(rest.sub(/(_is)?_not_checked$/, "")), "off")
						else
							verify_value(get_locator(rest.sub(/(_is)?_checked$/, "")), "on")
						end
					when "visible"
						verify_visible(get_locator(rest.sub(/(_is)?_visible$/, "")))
					when "invisible"
						verify_not_visible(get_locator(rest.sub(/(_is)?_invisible$/, "")))
					else
						verify_value(locator, args[0])
				end
			when "set"
				set_value(locator, args[0])
			when "get"
				get_value(locator)
			when "click"
				click(locator)
			else
				locator = get_locator(name.to_s)
				return (args.empty?() ? get_value(locator) : set_value(locator, args[0]))
		end
	end
end
